/*	FileChooserPanel.java
 *
 *	Copyright (c) Manateem Challenge Group, Zaia Group, and contributors 2010
 *
 *	This file is part of MSGSwingSet ('this project').
 *
 *	This project is free software: you can redistribute it and/or modify it
 *	under the terms of the GNU General Public License as published by the Free
 *	Software Foundation, either version 3 of the License, or (at your option)
 *	any later version.
 *
 *	This project is distributed in the hope that it will be useful, but WITHOUT
 *	ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *	FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 *	more details.
 *
 *	You should have received a copy of the GNU General Public License along with
 *	this project. If not, see <http://www.gnu.org/licenses/>.
 */
package edu.bu.manateem.msg.gui.component;

// Imports
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.prefs.Preferences;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.filechooser.FileFilter;

import edu.bu.manateem.msg.MSGConstants;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *	<p>
 *	A simple GUI for a file chooser. Allows the user to select a file (purpose
 *	left to concrete subclasses).
 *	</p>
 *
 *
 *	@author
 *		Christopher Jacobs
 *
 *	@version
 *		1.0
 *
 *	@changelog
 *		May 13, 2010	- Version 1.0.
 */
public abstract class FileChooserPanel
extends JPanel
implements ActionListener
{
	/*
	 * TYPES
	 */

	/*
	 * CONSTANTS
	 */

	// Serialize
	private static final long serialVersionUID = 1L;
	// Logging
	private static final Logger LOG =
		LoggerFactory.getLogger(FileChooserPanel.class);

	// actions
	private static final String CHOOSE = "choose";

	// default values
	private static final String PATH = "<no file chosen>";
	private static final String LAST_CHOSEN_FILE = "lastChosenFile";

	/*
	 * FIELDS
	 */
	private Preferences preferences = Preferences.systemNodeForPackage(this.getClass());
	private JButton fileButton = new JButton("Choose FIle");
	private JLabel fileLabel = new JLabel(
			preferences.get(LAST_CHOSEN_FILE, FileChooserPanel.PATH));

	private JFileChooser fileChooser = new JFileChooser(MSGConstants.USER_DIR);

	/*
	 * CONSTRUCTORS
	 */

	public FileChooserPanel()
	{
		super();

		FileChooserPanel.LOG.debug("init class");
		initFileChooser();
		init();
	}

	/*
	 * INITIALIZERS
	 */

	/*
	 * METHODS
	 */

	/**
	 *	<p>
	 *	Invoked when an action occurs.
	 *	</p>
	 *
	 *	@since
	 *		1.0
	 */
	@Override
	public void actionPerformed(ActionEvent e)
	{
		FileChooserPanel.LOG.info("button pressed for action -- {}",
				e.getActionCommand());
		if (FileChooserPanel.CHOOSE.equals(e.getActionCommand()))
		{
			if (showDialog() == JFileChooser.APPROVE_OPTION)
			{
				try
				{
					String filePath = fileChooser.getSelectedFile().getCanonicalPath();
					// remember path 
					preferences.put(LAST_CHOSEN_FILE, filePath);
					fileLabel.setText(filePath);
				}
				catch (IOException x)
				{
					FileChooserPanel.LOG.error(
							"cannot buld canonical path for file {}",
							fileChooser.getSelectedFile().getName());
				}
			}
		}
	}

	public void clear()
	{
		fileLabel.setText(FileChooserPanel.PATH);
	}

	public String getCanonicalPath()
	{
		String path = FileChooserPanel.PATH;
		try
		{
			path = getPath();
		}
		catch (IOException x)
		{
			return FileChooserPanel.PATH;
		}

		return path;
	}

	/**
	 *	<p>
	 *	Gets the file chooser.
	 *	</p>
	 *
	 *	@since
	 *		1.0
	 *
	 *
	 *	@return
	 *		the file chooser.
	 */
	public JFileChooser getFileChooser()
	{
		FileChooserPanel.LOG.debug("getting file chooser");
		return fileChooser;
	}

	/**
	 *	<p>
	 *	Gets the canonical (absolute) path to the selected file.
	 *	</p>
	 *
	 *	@since
	 *		1.0
	 *
	 *
	 *	@return
	 *		the canonical path to the file selected.
	 *
	 *
	 *	@throws
	 *		IOException
	 */
	public String getPath()
	throws IOException
	{
		FileChooserPanel.LOG.debug("getting canonical pathway of file");
		if (fileLabel.getText().equalsIgnoreCase(FileChooserPanel.PATH))
		{
			return null;
		}
		
		else if (fileLabel.getText() != null)
		{
			// returns previously used path
			return fileLabel.getText();
		}
		
		return fileChooser.getSelectedFile().getCanonicalPath();
	}

	/**
	 *	<p>
	 *	Initializes the "master" frame of <code>this</code> object. Sets the
	 *	default panel behaviors and layout, and packs components.
	 *	</p>
	 *
	 *	@since
	 *		1.0
	 */
	private void init()
	{
		FileChooserPanel.LOG.debug("build container");

		// behavior

		// layout
		setLayout(new BoxLayout(this,BoxLayout.X_AXIS));

		// finish
		add(fileButton);
		add(Box.createRigidArea(new Dimension(10,5)));
		add(fileLabel);
		FileChooserPanel.LOG.debug("build container -- DONE");
	}

	/**
	 *	<p>
	 *	Initializes the file chooser (browser), and its directly associated
	 *	components for <code>this</code> object.
	 *	</p>
	 *
	 *	@since
	 *		1.0
	 */
	private void initFileChooser()
	{
		FileChooserPanel.LOG.debug("build file chooser");

		// accesories
		fileButton.addActionListener(this);
		fileButton.setActionCommand(FileChooserPanel.CHOOSE);

		// behavior
		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
		FileChooserPanel.LOG.debug("build file chooser -- DONE");
	}

	/**
	 *	<p>
	 *	Sets the file chooser.
	 *	</p>
	 *
	 *	@since
	 *		1.0
	 *
	 *
	 *	@param
	 *		fileChooser	- the new file chooser.
	 */
	public void setFileChooser(JFileChooser fileChooser)
	{
		FileChooserPanel.LOG.debug("setting file chooser");
		this.fileChooser = fileChooser;
	}

	/**
	 *	<p>
	 *	Sets the current file filter.
	 *	</p>
	 *
	 *	@see
	 *		javax.swing.JFileChooser#setFileFilter(FileFilter)
	 *
	 *	@since
	 *		1.0
	 *
	 *
	 *	@param
	 *		description	- description of this file filter (appears in dialog)
	 *	@param
	 *		allowableExtensions	- the file extensions to filter for
	 */
	public void setFileFilter(final String description,
			final String...allowableExtensions)
	{
		FileChooserPanel.LOG.debug("setting file filter");
		fileChooser.setAcceptAllFileFilterUsed(false);
		fileChooser.setFileFilter(new FileFilter()
		{
			@Override
			public boolean accept(File file)
			{
				if (file.isDirectory())
				{
					return true;
				}

				for (String extension : allowableExtensions)
				{
					if (file.getName().toLowerCase().endsWith(
							"." + extension.toLowerCase()))
					{
						return true;
					}
				}
				return false;
			}

			/**
			 *	<p>
			 *	The description of this filter.
			 *	</p>
			 *
			 *	@since
			 *		1.0
			 */
			@Override
			public String getDescription()
			{
				return description;
			}
		});
	}

	/**
	 *	<p>
	 *	Shows the appropriate dialog for the file chooser type. File chooser
	 *	type is determined by inheriting classes based on their functionality
	 *	(e.g. saving, loading,etc.).
	 *	</p>
	 *
	 *	@since
	 *		1.0
	 */
	public abstract int showDialog();
}
